package com.rupertjones.globalcron.quartz;

import com.rupertjones.globalcron.domain.Executable;
import com.rupertjones.globalcron.domain.ExecutionContext;
import com.rupertjones.globalcron.domain.JobDescriptor;
import com.rupertjones.globalcron.domain.JobExecutionListener;
import org.apache.log4j.Logger;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.StatefulJob;
import org.springframework.scheduling.quartz.QuartzJobBean;

import static com.rupertjones.globalcron.domain.Host.getCurrentHost;
import static java.lang.String.format;

public class QuartzJob extends QuartzJobBean implements StatefulJob {
    private JobExecutionContext context;
    private JobDescriptor jobDescriptor;
    private static final Logger LOG = Logger.getLogger(QuartzJob.class);
    private JobExecutionListener listener;

    public void setJobDescriptor(JobDescriptor jobDescriptor) {
        this.jobDescriptor = jobDescriptor;
    }

    public void setJobExecutionListener(JobExecutionListener listener) {
        this.listener = listener;
    }

    public JobDescriptor getJobDescriptor() {
        return jobDescriptor;
    }

    public String getSummary() {
        return "[" + jobDescriptor.getId() + " " + jobDescriptor.getName() + "] using [cron "
                + jobDescriptor.getCron() + "@"
                + jobDescriptor.getTimezone() + "]";
    }

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        if (jobDescriptor.runOnHost(getCurrentHost()))  {
            LOG.info("Executing: " + getSummary());
            Executable runnable = jobDescriptor.getRunnable();
            long start = System.currentTimeMillis();
            runnable.run();
            long end = System.currentTimeMillis();
            ExecutionContext executionContext = new ExecutionContext();
            executionContext.setJobDescriptor(jobDescriptor);
            executionContext.setTimeTaken((end - start));
            executionContext.setOutput(runnable.getOutput());
            executionContext.setExecutedNormally(runnable.executedNormally());
            executionContext.setNextFire(context.getNextFireTime());
            executionContext.setLastFire(context.getFireTime());
            afterExecution(executionContext);
            LOG.info("Completed Executing: " + getSummary() + " in " + executionContext.getTimeTaken() + "ms, Next Fire Time: " + context.getNextFireTime());
        } else {
            LOG.debug(format("Not executing [%s] - belongs to other host.", getSummary()));
        }
    }

    private void afterExecution(ExecutionContext executionContext) {
        if (listener != null) {
            listener.afterExecution(executionContext);
        }
    }
}
